package com.dream.libxrec.encode.video;

import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;

public class H264Encoder extends IVideoEncoder{

    private static final String TAG = "VideoEncoder";
    private final static String MIME_TYPE =
            MediaFormat.MIMETYPE_VIDEO_AVC;
    private static final long DEFAULT_TIMEOUT_US = 10000;

    private MediaCodec mEncoder;

    private boolean mStop = true;
    private IVideoEncoderListener listener = null;

    @Override
    public void init(Context ct, int width, int height,
                     boolean isVBR, int bitRate) {
        try {
            mStop = true;
            mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
            MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);
            mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar);

            //帧率设置一般没有效果，一般情况下，如果要控制帧率，最好是通过控制输入数据源的输入频率
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
            // 设置码控模式
            mediaFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,isVBR?
                    MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR:MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);

            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);

            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
//          设置压缩等级,默认是baseline
            mediaFormat.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileMain);
//            mediaFormat.setInteger(MediaFormat.KEY_LEVEL,
//                    MediaCodecInfo.CodecProfileLevel.AVCLevel4);

            mEncoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public synchronized void addIEncoderListener(IVideoEncoderListener listener) {
        this.listener = listener;
    }

    @Override
    public synchronized void start(){
        if (mEncoder != null){
            mStop = false;
            mEncoder.start();
        }
    }

    @Override
    public synchronized boolean isRun() {
        return !mStop;
    }

    public static void printSupportTypes() {
        MediaCodecList allMediaCodecLists = new MediaCodecList(-1);
        MediaCodecInfo avcCodecInfo = null;
        for (MediaCodecInfo mediaCodecInfo : allMediaCodecLists.getCodecInfos()) {
            if (mediaCodecInfo.isEncoder()) {
                String[] supportTypes = mediaCodecInfo.getSupportedTypes();
                for (String supportType : supportTypes) {
                    if (supportType.equals(MediaFormat.MIMETYPE_VIDEO_AVC)) {
                        avcCodecInfo = mediaCodecInfo;
                        Log.d(TAG,
                                "编码器名称:" + mediaCodecInfo.getName() + "  " + supportType);
                        MediaCodecInfo.CodecCapabilities codecCapabilities = avcCodecInfo.getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AVC);
                        int[] colorFormats = codecCapabilities.colorFormats;
                        for (int colorFormat : colorFormats) {
                            switch (colorFormat) {
                                case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV411Planar:
                                case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV411PackedPlanar:
                                case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
                                case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
                                case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
                                case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
                                    Log.d(TAG,
                                            "支持的格式::" + colorFormat);
                                    break;
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public synchronized void stop() {
        mStop = true;
        try {
            if (mEncoder != null) {
                mEncoder.stop();
                mEncoder.release();
                mEncoder = null;
            }
        }catch (Exception ignored){}
    }

    public synchronized void encode(byte[] nv12,int offset,int size) {
        encode(nv12,offset,size,System.nanoTime()/1000);
    }

    /**
     *
     * @param nv12 YUV数据，根据情况可能为NV12或I420
     * @param presentationTimeUs 时间戳，微秒（一般情况下为当前时间 - 第一帧的时间）
     */
    public synchronized void encode(byte[] nv12,int offset,int size, long presentationTimeUs) {
        if (mStop){
            return;
        }

        if (mEncoder == null) {
            Log.e(TAG, "mEncoder or mMediaMuxer is null");
            return;
        }
        if (nv12 == null) {
            Log.e(TAG, "input yuv data is null");
            return;
        }

        int inputBufferIndex = mEncoder.dequeueInputBuffer(DEFAULT_TIMEOUT_US);
        if (inputBufferIndex < 0) {
            Log.e(TAG, "no valid buffer available");
            return;
        }

        ByteBuffer inputBuffer = mEncoder.getInputBuffer(inputBufferIndex);
        inputBuffer.clear();
        inputBuffer.put(nv12);

        mEncoder.queueInputBuffer(inputBufferIndex, offset,size,
                presentationTimeUs, 0);

        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = this.mEncoder.dequeueOutputBuffer(bufferInfo,DEFAULT_TIMEOUT_US);
        if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat outputFormat = mEncoder.getOutputFormat();
            if (listener != null){
                listener.onFormat(outputFormat);
            }
        }

        while (outputBufferIndex >= 0) {
            ByteBuffer buffer = this.mEncoder.getOutputBuffer(outputBufferIndex);

            if (buffer != null){
                if (listener!= null){
                    listener.onFrame(buffer,bufferInfo);
                }
            }

            this.mEncoder.releaseOutputBuffer(outputBufferIndex, false);
            outputBufferIndex = this.mEncoder.dequeueOutputBuffer(bufferInfo, DEFAULT_TIMEOUT_US);
            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                break;
            }
        }
    }
}
